package com.demo.javacv.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import org.bytedeco.ffmpeg.avcodec.AVPacket;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;

public interface FFmpegUtil {

    /**
     * 获取关键帧图片
     */
    static File getKeyFrameByVideoFile(File inputFile) throws IOException {
        try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile)) {
            grabber.start();
            // 获取关键帧
            Frame firstFrame = grabber.grabKeyFrame();
            if (firstFrame == null) {
                return null;
            }

            // 将帧转换为BufferedImage
            try (Java2DFrameConverter converter = new Java2DFrameConverter()) {
                BufferedImage bufferedImage = converter.convert(firstFrame);
                if (bufferedImage == null) {
                    return null;
                }

                String captureDir = inputFile.getParentFile().getAbsolutePath()
                        + File.separator + "capture" + File.separator + IdUtil.getSnowflakeNextId();
                if (!FileUtil.exist(captureDir)) {
                    FileUtil.mkdir(captureDir);
                }

                String outputPath = captureDir + File.separator + inputFile.getName().replaceFirst("[.][^.]+$", "") + ".jpg";
                File outputFile = Path.of(outputPath).toFile();
                ImageIO.write(bufferedImage, "jpg", outputFile);
                return outputFile;
            }
        }
    }

    /**
     * 获取视频时长 单位/秒
     */
    static long getVideoDuration(File inputFile) throws FrameGrabber.Exception {
        try (FFmpegFrameGrabber ff = new FFmpegFrameGrabber(inputFile)) {
            ff.start();
            return ff.getLengthInTime() / (1000 * 1000);
        }
    }

    /**
     * 将视频转换为m3u8
     *
     * @return m3u8文件路径
     */
    static File convertVideoFile2M3u8File(File inputFile) throws IOException {
        try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile)) {
            grabber.start();
            return convertVideoFile2M3u8File(grabber, inputFile);
        }
    }

    private static File convertVideoFile2M3u8File(FFmpegFrameGrabber grabber, File inputFile) throws IOException {
        String m3u8Dir = inputFile.getParentFile().getAbsolutePath()
                + File.separator + "m3u8" + File.separator + IdUtil.getSnowflakeNextId();
        if (!FileUtil.exist(m3u8Dir)) {
            FileUtil.mkdir(m3u8Dir);
        }

        String prefix = m3u8Dir + File.separator + inputFile.getName().replaceFirst("[.][^.]+$", "");

        final File m3u8File = Path.of(prefix + ".m3u8").toFile();
        try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
                m3u8File, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels())
        ) {
            //格式方式
            recorder.setFormat("hls");
            //关于hls_wrap的说明，hls_wrap表示重复覆盖之前ts切片，这是一个过时配置，ffmpeg官方推荐使用hls_list_size 和hls_flags delete_segments代替hls_wrap
            //设置单个ts切片的时间长度（以秒为单位）。默认值为2秒
            recorder.setOption("hls_time", "15");
            //不根据gop间隔进行切片,强制使用hls_time时间进行切割ts分片
            recorder.setOption("hls_flags", "split_by_time");

            //设置播放列表条目的最大数量。如果设置为0，则列表文件将包含所有片段，默认值为5 当切片的时间不受控制时，切片数量太小，就会有卡顿的现象
            recorder.setOption("hls_list_size", "0");
            //自动删除切片，如果切片数量大于hls_list_size的数量，则会开始自动删除之前的ts切片，只保留hls_list_size个数量的切片
            recorder.setOption("hls_flags", "delete_segments");
            //ts切片自动删除阈值，默认值为1，表示早于hls_list_size+1的切片将被删除
            recorder.setOption("hls_delete_threshold", "1");
            /*hls的切片类型：
             * 'mpegts'：以MPEG-2传输流格式输出ts切片文件，可以与所有HLS版本兼容。
             * 'fmp4':以Fragmented MP4(简称：fmp4)格式输出切片文件，类似于MPEG-DASH，fmp4文件可用于HLS version 7和更高版本。
             */
            recorder.setOption("hls_segment_type", "mpegts");
            //指定ts切片生成名称规则，按数字序号生成切片,例如'file%03d.ts'，就会生成file000.ts，file001.ts，file002.ts等切片文件
            recorder.setOption("hls_segment_filename", prefix + "-%6d.ts");

            // 快速
            recorder.setVideoOption("tune", "fastdecode");
            recorder.setVideoOption("preset", "ultrafast");
            recorder.setVideoOption("threads", "12");
            recorder.setVideoOption("vsync", "2");
            recorder.setFrameRate(grabber.getFrameRate());// 设置帧率
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);

            // 转码
            System.out.println("启动Hls转码录制器......");
            recorder.start(grabber.getFormatContext());
            AVPacket packet;
            while ((packet = grabber.grabPacket()) != null) {
                recorder.recordPacket(packet);
            }

            recorder.setTimestamp(grabber.getTimestamp());
        }

        return m3u8File;
    }

}
